#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <cassert>
#include <functional>

#include "../include/CLink/database/ORM.h"
#include "../include/CLink/database/DatabaseManager.h"

/**
 * @brief 学生模型类
 * 
 * 演示ORM基本功能的学生模型
 */
class Student : public CLink::Db::Model {
public:
    Student() : Model() {}
    
    // 创建模型实例
    Ptr create() override {
        return std::make_shared<Student>();
    }
    
    // 获取表名
    std::string getTableName() const override {
        return "students";
    }
    
    // 获取主键
    std::string getPrimaryKey() const override {
        return "id";
    }
    
    // 定义字段
    std::vector<CLink::Db::FieldDefinition> getFields() const override {
        return {
            {"id", CLink::Db::FieldType::INTEGER, false, true, true, "", 0},
            {"name", CLink::Db::FieldType::TEXT, false, false, false, "", 50},
            {"age", CLink::Db::FieldType::INTEGER, false, false, false, "0", 0},
            {"email", CLink::Db::FieldType::TEXT, true, false, false, "", 100},
            {"grade", CLink::Db::FieldType::INTEGER, false, false, false, "1", 0},
            {"created_at", CLink::Db::FieldType::DATETIME, false, false, false, "CURRENT_TIMESTAMP", 0}
        };
    }
    
    // 定义验证规则
    std::vector<CLink::Db::ValidationRule> getValidationRules() const override {
        return {
            {
                "name", 
                {
                    [](const std::string& value) { return !value.empty(); },
                    [](const std::string& value) { return value.length() <= 50; }
                },
                "Student name is required and must be less than 50 characters"
            },
            {
                "age",
                {
                    [](const std::string& value) { 
                        try {
                            int age = std::stoi(value);
                            return age > 0 && age < 100;
                        } catch (...) {
                            return false;
                        }
                    }
                },
                "Age must be a positive number less than 100"
            },
            {
                "email",
                {
                    [](const std::string& value) { 
                        if (value.empty()) return true; // 允许为空
                        return value.find('@') != std::string::npos; 
                    }
                },
                "Email must be a valid email address"
            },
            {
                "grade",
                {
                    [](const std::string& value) { 
                        try {
                            int grade = std::stoi(value);
                            return grade >= 1 && grade <= 12;
                        } catch (...) {
                            return false;
                        }
                    }
                },
                "Grade must be between 1 and 12"
            }
        };
    }
    
    // 定义关系
    std::map<std::string, CLink::Db::RelationDefinition> getRelations() const override {
        return {
            {
                "scores", 
                {
                    CLink::Db::RelationType::HAS_MANY,
                    "Score",
                    "student_id",
                    "id",
                    "",
                    "",
                    ""
                }
            }
        };
    }
    
    // 便捷方法
    void setName(const std::string& name) {
        setAttribute("name", name);
    }
    
    std::string getName() const {
        return getAttribute("name");
    }
    
    void setAge(int age) {
        setAttribute("age", std::to_string(age));
    }
    
    int getAge() const {
        try {
            return std::stoi(getAttribute("age"));
        } catch (...) {
            return 0;
        }
    }
    
    void setEmail(const std::string& email) {
        setAttribute("email", email);
    }
    
    std::string getEmail() const {
        return getAttribute("email");
    }
    
    void setGrade(int grade) {
        setAttribute("grade", std::to_string(grade));
    }
    
    int getGrade() const {
        try {
            return std::stoi(getAttribute("grade"));
        } catch (...) {
            return 1;
        }
    }
};

/**
 * @brief 成绩模型类
 * 
 * 演示ORM关系功能的成绩模型
 */
class Score : public CLink::Db::Model {
public:
    Score() : Model() {}
    
    // 创建模型实例
    Ptr create() override {
        return std::make_shared<Score>();
    }
    
    // 获取表名
    std::string getTableName() const override {
        return "scores";
    }
    
    // 获取主键
    std::string getPrimaryKey() const override {
        return "id";
    }
    
    // 定义字段
    std::vector<CLink::Db::FieldDefinition> getFields() const override {
        return {
            {"id", CLink::Db::FieldType::INTEGER, false, true, true, "", 0},
            {"student_id", CLink::Db::FieldType::INTEGER, false, false, false, "", 0},
            {"subject", CLink::Db::FieldType::TEXT, false, false, false, "", 50},
            {"score", CLink::Db::FieldType::FLOAT, false, false, false, "0.0", 0},
            {"exam_date", CLink::Db::FieldType::DATETIME, true, false, false, "", 0},
            {"created_at", CLink::Db::FieldType::DATETIME, false, false, false, "CURRENT_TIMESTAMP", 0}
        };
    }
    
    // 定义验证规则
    std::vector<CLink::Db::ValidationRule> getValidationRules() const override {
        return {
            {
                "student_id", 
                {
                    [](const std::string& value) { return !value.empty(); }
                },
                "Student ID is required"
            },
            {
                "subject", 
                {
                    [](const std::string& value) { return !value.empty(); }
                },
                "Subject is required"
            },
            {
                "score", 
                {
                    [](const std::string& value) { 
                        try {
                            float score = std::stof(value);
                            return score >= 0.0f && score <= 100.0f;
                        } catch (...) {
                            return false;
                        }
                    }
                },
                "Score must be between 0 and 100"
            }
        };
    }
    
    // 定义关系
    std::map<std::string, CLink::Db::RelationDefinition> getRelations() const override {
        return {
            {
                "student", 
                {
                    CLink::Db::RelationType::BELONGS_TO,
                    "Student",
                    "id",
                    "student_id",
                    "",
                    "",
                    ""
                }
            }
        };
    }
    
    // 便捷方法
    void setStudentId(const std::string& studentId) {
        setAttribute("student_id", studentId);
    }
    
    std::string getStudentId() const {
        return getAttribute("student_id");
    }
    
    void setSubject(const std::string& subject) {
        setAttribute("subject", subject);
    }
    
    std::string getSubject() const {
        return getAttribute("subject");
    }
    
    void setScore(float score) {
        setAttribute("score", std::to_string(score));
    }
    
    float getScore() const {
        try {
            return std::stof(getAttribute("score"));
        } catch (...) {
            return 0.0f;
        }
    }
    
    void setExamDate(const std::string& examDate) {
        setAttribute("exam_date", examDate);
    }
    
    std::string getExamDate() const {
        return getAttribute("exam_date");
    }
};

/**
 * @brief ORM功能测试函数
 * 
 * 测试学生和成绩模型的各种ORM功能
 */
void testORM() {
    std::cout << "=== ORM Test: Student and Score Models ===" << std::endl;
    
    // 创建数据库表
    std::cout << "Creating tables..." << std::endl;
    bool studentTableCreated = CLink::Db::Model::createTable<Student>();
    bool scoreTableCreated = CLink::Db::Model::createTable<Score>();
    
    if (!studentTableCreated || !scoreTableCreated) {
        std::cerr << "Failed to create tables!" << std::endl;
        return;
    }
    
    // 检查表是否存在
    bool studentTableExists = CLink::Db::Model::tableExists<Student>();
    bool scoreTableExists = CLink::Db::Model::tableExists<Score>();
    
    std::cout << "Student table exists: " << (studentTableExists ? "Yes" : "No") << std::endl;
    std::cout << "Score table exists: " << (scoreTableExists ? "Yes" : "No") << std::endl;
    
    // 创建学生记录
    std::cout << "\nCreating student records..." << std::endl;
    
    auto student1 = std::make_shared<Student>();
    student1->setName("Alice Smith");
    student1->setAge(16);
    student1->setEmail("alice.smith@example.com");
    student1->setGrade(10);
    
    if (!student1->validate()) {
        std::cerr << "Validation failed for student1:" << std::endl;
        for (const auto& error : student1->getErrors()) {
            std::cerr << "- " << error << std::endl;
        }
    } else {
        bool saved = student1->save();
        std::cout << "Student 1 saved: " << (saved ? "Yes" : "No") << std::endl;
    }
    
    auto student2 = std::make_shared<Student>();
    student2->setName("Bob Johnson");
    student2->setAge(17);
    student2->setEmail("bob.johnson@example.com");
    student2->setGrade(11);
    
    if (!student2->validate()) {
        std::cerr << "Validation failed for student2:" << std::endl;
        for (const auto& error : student2->getErrors()) {
            std::cerr << "- " << error << std::endl;
        }
    } else {
        bool saved = student2->save();
        std::cout << "Student 2 saved: " << (saved ? "Yes" : "No") << std::endl;
    }
    
    // 测试验证失败的情况
    std::cout << "\nTesting validation failure..." << std::endl;
    auto invalidStudent = std::make_shared<Student>();
    invalidStudent->setName("");  // 名字为空，应该验证失败
    invalidStudent->setAge(150);  // 年龄超出范围，应该验证失败
    invalidStudent->setEmail("invalid-email");  // 无效的邮箱格式，应该验证失败
    
    if (!invalidStudent->validate()) {
        std::cout << "Validation failed as expected for invalid student:" << std::endl;
        for (const auto& error : invalidStudent->getErrors()) {
            std::cout << "- " << error << std::endl;
        }
    } else {
        std::cerr << "Validation unexpectedly passed for invalid student!" << std::endl;
    }
    
    // 查询学生记录
    std::cout << "\nQuerying student records..." << std::endl;
    auto students = CLink::Db::Model::all<Student>();
    std::cout << "Found " << students.size() << " students:" << std::endl;
    
    for (const auto& student : students) {
        std::cout << "ID: " << student->getAttribute("id")
                  << ", Name: " << student->getName()
                  << ", Age: " << student->getAge()
                  << ", Grade: " << student->getGrade()
                  << ", Email: " << student->getEmail() << std::endl;
    }
    
    // 添加成绩记录
    std::cout << "\nAdding score records..." << std::endl;
    
    if (!students.empty()) {
        auto student1Id = students[0]->getAttribute("id");
        
        auto mathScore = std::make_shared<Score>();
        mathScore->setStudentId(student1Id);
        mathScore->setSubject("Mathematics");
        mathScore->setScore(92.5f);
        mathScore->setExamDate("2023-05-15 10:00:00");
        
        if (!mathScore->validate()) {
            std::cerr << "Validation failed for math score:" << std::endl;
            for (const auto& error : mathScore->getErrors()) {
                std::cerr << "- " << error << std::endl;
            }
        } else {
            bool saved = mathScore->save();
            std::cout << "Math score saved: " << (saved ? "Yes" : "No") << std::endl;
        }
        
        auto scienceScore = std::make_shared<Score>();
        scienceScore->setStudentId(student1Id);
        scienceScore->setSubject("Science");
        scienceScore->setScore(88.0f);
        scienceScore->setExamDate("2023-05-16 14:00:00");
        
        if (!scienceScore->validate()) {
            std::cerr << "Validation failed for science score:" << std::endl;
            for (const auto& error : scienceScore->getErrors()) {
                std::cerr << "- " << error << std::endl;
            }
        } else {
            bool saved = scienceScore->save();
            std::cout << "Science score saved: " << (saved ? "Yes" : "No") << std::endl;
        }
        
        if (students.size() > 1) {
            auto student2Id = students[1]->getAttribute("id");
            
            auto englishScore = std::make_shared<Score>();
            englishScore->setStudentId(student2Id);
            englishScore->setSubject("English");
            englishScore->setScore(95.0f);
            englishScore->setExamDate("2023-05-15 09:00:00");
            englishScore->save();
            
            auto historyScore = std::make_shared<Score>();
            historyScore->setStudentId(student2Id);
            historyScore->setSubject("History");
            historyScore->setScore(78.5f);
            historyScore->setExamDate("2023-05-17 11:00:00");
            historyScore->save();
        }
    }
    
    // 查询成绩记录
    std::cout << "\nQuerying score records..." << std::endl;
    auto scores = CLink::Db::Model::all<Score>();
    std::cout << "Found " << scores.size() << " scores:" << std::endl;
    
    for (const auto& score : scores) {
        std::cout << "ID: " << score->getAttribute("id")
                  << ", Student ID: " << score->getStudentId()
                  << ", Subject: " << score->getSubject()
                  << ", Score: " << score->getScore()
                  << ", Exam Date: " << score->getExamDate() << std::endl;
    }
    
    // 测试关系查询
    std::cout << "\nTesting relationship queries..." << std::endl;
    
    if (!students.empty()) {
        auto student = students[0];
        std::cout << "Getting scores for student: " << student->getName() << std::endl;
        
        // 使用hasMany关系查询
        auto studentScores = student->hasMany<Score>("student_id");
        std::cout << "Found " << studentScores.size() << " scores for this student:" << std::endl;
        
        for (const auto& score : studentScores) {
            std::cout << "Subject: " << score->getSubject()
                      << ", Score: " << score->getScore() << std::endl;
        }
        
        // 使用getRelated方法查询
        auto relatedScores = student->getRelated<Score>("scores");
        std::cout << "Found " << relatedScores.size() << " scores using getRelated:" << std::endl;
        
        for (const auto& score : relatedScores) {
            std::cout << "Subject: " << score->getSubject()
                      << ", Score: " << score->getScore() << std::endl;
        }
    }
    
    if (!scores.empty()) {
        auto score = scores[0];
        std::cout << "\nGetting student for score: " << score->getSubject() << std::endl;
        
        // 使用belongsTo关系查询
        auto student = score->belongsTo<Student>("student_id");
        if (student) {
            std::cout << "Found student: " << student->getName() << std::endl;
        } else {
            std::cout << "No student found for this score." << std::endl;
        }
        
        // 使用getRelatedOne方法查询
        auto relatedStudent = score->getRelatedOne<Student>("student");
        if (relatedStudent) {
            std::cout << "Found student using getRelatedOne: " << relatedStudent->getName() << std::endl;
        } else {
            std::cout << "No student found using getRelatedOne." << std::endl;
        }
    }
    
    // 测试更新记录
    std::cout << "\nTesting record updates..." << std::endl;
    
    if (!students.empty()) {
        auto student = students[0];
        std::cout << "Updating student: " << student->getName() << std::endl;
        
        student->setGrade(student->getGrade() + 1);
        bool updated = student->update({{"grade", std::to_string(student->getGrade())}});
        std::cout << "Student updated: " << (updated ? "Yes" : "No") << std::endl;
        
        // 重新查询以验证更新
        auto updatedStudent = CLink::Db::Model::find<Student>(student->getAttribute("id"));
        if (updatedStudent) {
            std::cout << "Updated student grade: " << updatedStudent->getGrade() << std::endl;
        }
    }
    
    // 测试条件查询
    std::cout << "\nTesting conditional queries..." << std::endl;
    
    auto highScores = CLink::Db::Model::where<Score>("score", CLink::Db::OperatorType::GREATER_THAN, "90");
    std::cout << "Found " << highScores.size() << " scores above 90:" << std::endl;
    
    for (const auto& score : highScores) {
        std::cout << "Subject: " << score->getSubject()
                  << ", Score: " << score->getScore() << std::endl;
    }
    
    // 测试删除记录
    std::cout << "\nTesting record deletion..." << std::endl;
    
    if (!scores.empty()) {
        auto score = scores.back();
        std::cout << "Deleting score: " << score->getSubject() << " with ID: " << score->getAttribute("id") << std::endl;
        
        bool removed = score->remove();
        std::cout << "Score removed: " << (removed ? "Yes" : "No") << std::endl;
        
        // 重新查询以验证删除
        auto remainingScores = CLink::Db::Model::all<Score>();
        std::cout << "Remaining scores count: " << remainingScores.size() << std::endl;
    }
    
    // 清理测试数据
    std::cout << "\nCleaning up test data..." << std::endl;
    
    bool scoreTableDropped = CLink::Db::Model::dropTable<Score>();
    bool studentTableDropped = CLink::Db::Model::dropTable<Student>();
    
    std::cout << "Score table dropped: " << (scoreTableDropped ? "Yes" : "No") << std::endl;
    std::cout << "Student table dropped: " << (studentTableDropped ? "Yes" : "No") << std::endl;
    
    std::cout << "\n=== ORM Test Completed ===" << std::endl;
}
